﻿/*
** Xin YUAN, 2021, BSD (2)
*/

////////////////////////////////////////////////////////////////////////////////
#ifndef __CTL_TRAITS_H__
#define __CTL_TRAITS_H__
////////////////////////////////////////////////////////////////////////////////

#include "base/GkcAlg.h"

#include "sys/GkcSysDef.h"
#include "sys/GkcSys.h"

////////////////////////////////////////////////////////////////////////////////

// Basic Types

#define int8_t     char
#define uint8_t    byte
#define int16_t    short
#define uint16_t   ushort
#define int32_t    int
#define uint32_t   uint
#define int64_t    int64
#define uint64_t   uint64
#define intptr_t   intptr
#define uintptr_t  uintptr
/*
=== in GkcDef.h ===
char_s
=== C/C++ ===
char
*/

// Macros

/*
=== C/C++ ===
assert
*/
#define _s(x)  _S(x)

// Functions

/*
=== GkcDef.h ===

template <typename T>
inline T&& rv_forward(T& t) noexcept

template <typename T, typename... Args>
inline void call_constructor(T& t, Args&&... args)

template <typename T>
inline void call_destructor(T& t) noexcept

inline void thread_sleep(uint32_t tm) noexcept;
*/

////////////////////////////////////////////////////////////////////////////////
namespace CTL {
////////////////////////////////////////////////////////////////////////////////

// Operators

template <typename T>
class NumericTraits
{
public:
	static constexpr const T MinValue = GKC::Limits<T>::Lowest;
	static constexpr const T MaxValue = GKC::Limits<T>::Max;
};

template <typename T>
class ArithmeticTraits
{
public:
	static bool Add(T t1, T t2, T& r) noexcept
	{
		return GKC::SafeOperators::Add(t1, t2, r).IsSucceeded();
	}
	static bool Multiply(T t1, T t2, T& r) noexcept
	{
		return GKC::SafeOperators::Multiply(t1, t2, r).IsSucceeded();
	}
	static T AddThrow(T t1, T t2)
	{
		return GKC::SafeOperators::AddThrow(t1, t2);  //may throw
	}
	static T MultiplyThrow(T t1, T t2)
	{
		return GKC::SafeOperators::MultiplyThrow(t1, t2);  //may throw
	}
};

template <typename T>
class NumberTraits
{
public:
	static T Abs(T t) noexcept
	{
		return GKC::NumberHelper::Abs(t);
	}
	static bool IsOdd(T t) noexcept
	{
		return GKC::NumberHelper::IsOdd<T>(t);
	}
};

template <typename T>
class FloatTraits
{
public:
	static bool isfinite(T t) noexcept
	{
		return GKC::FloatHelper::IsFinite(t);
	}
	static T acos(T t) noexcept
	{
		return GKC::FloatHelper::acos(t);
	}
	static T acosh(T t) noexcept
	{
		return GKC::FloatHelper::acosh(t);
	}
	static T asin(T t) noexcept
	{
		return GKC::FloatHelper::asin(t);
	}
	static T asinh(T t) noexcept
	{
		return GKC::FloatHelper::asinh(t);
	}
	static T atan2(T t1, T t2) noexcept
	{
		return GKC::FloatHelper::atan2(t1, t2);
	}
	static T atanh(T t) noexcept
	{
		return GKC::FloatHelper::atanh(t);
	}
	static T cos(T t) noexcept
	{
		return GKC::FloatHelper::cos(t);
	}
	static T cosh(T t) noexcept
	{
		return GKC::FloatHelper::cosh(t);
	}
	static T exp(T t) noexcept
	{
		return GKC::FloatHelper::exp(t);
	}
	static T ldexp(T t, int e) noexcept
	{
		return GKC::FloatHelper::ldexp(t, e);
	}
	static T log(T t) noexcept
	{
		return GKC::FloatHelper::log(t);
	}
	static T log10(T t) noexcept
	{
		return GKC::FloatHelper::log10(t);
	}
	static T log2(T t) noexcept
	{
		return GKC::FloatHelper::log2(t);
	}
	static T pow(T t1, T t2) noexcept
	{
		return GKC::FloatHelper::pow(t1, t2);
	}
	static T sin(T t) noexcept
	{
		return GKC::FloatHelper::sin(t);
	}
	static T sinh(T t) noexcept
	{
		return GKC::FloatHelper::sinh(t);
	}
	static T sqrt(T t) noexcept
	{
		return GKC::FloatHelper::sqrt(t);
	}
	static T tan(T t) noexcept
	{
		return GKC::FloatHelper::tan(t);
	}
	static T tanh(T t) noexcept
	{
		return GKC::FloatHelper::tanh(t);
	}
	static T ceil(T t) noexcept
	{
		return GKC::FloatHelper::ceil(t);
	}
	static T floor(T t) noexcept
	{
		return GKC::FloatHelper::floor(t);
	}
	static T round(T t) noexcept
	{
		return GKC::FloatHelper::round(t);
	}
	static T trunc(T t) noexcept
	{
		return GKC::FloatHelper::trunc(t);
	}
};

template <typename T>
using DefaultCompareTrait = GKC::DefaultCompareTrait<T>;

template <class TTrait>
class CompareTraits
{
public:
	typedef typename TTrait::EType  ValueType;
	typedef TTrait  TraitType;

	static bool EQ(const ValueType& t1, const ValueType& t2) noexcept
	{
		return TraitType::IsEQ(t1, t2);
	}
	static bool NE(const ValueType& t1, const ValueType& t2) noexcept
	{
		return TraitType::IsNE(t1, t2);
	}
	static bool LT(const ValueType& t1, const ValueType& t2) noexcept
	{
		return TraitType::IsLT(t1, t2);
	}
	static bool LE(const ValueType& t1, const ValueType& t2) noexcept
	{
		return TraitType::IsLE(t1, t2);
	}
	static bool GT(const ValueType& t1, const ValueType& t2) noexcept
	{
		return TraitType::IsGT(t1, t2);
	}
	static bool GE(const ValueType& t1, const ValueType& t2) noexcept
	{
		return TraitType::IsGE(t1, t2);
	}
	static int32_t Compare(const ValueType& t1, const ValueType& t2) noexcept
	{
		return TraitType::Compare(t1, t2);
	}
};

// Byte Order

class ByteOrderTraits
{
public:
	static bool IsBigEndianHost() noexcept
	{
		return GKC::ByteOrderHelper::IsBigEndianHost();
	}
	template <typename T>
	static T Swap(T x) noexcept
	{
		return GKC::ByteOrderHelper::Swap(x);
	}
};

// Memory

class MemoryTraits
{
public:
	static void Copy(const void* src, uintptr_t size, void* dest) noexcept
	{
		mem_copy(src, size, dest);
	}
	static void Move(const void* src, uintptr_t size, void* dest) noexcept
	{
		mem_move(src, size, dest);
	}
	static void Zero(void* dest, uintptr_t size) noexcept
	{
		mem_zero(dest, size);
	}
	static void Fill(uint8_t value, void* dest, uintptr_t size) noexcept
	{
		mem_fill(value, dest, size);
	}
};

// Exceptions

class ExceptionTraits
{
public:
	static void ThrowInvalid()
	{
		throw GKC::Exception(GKC::CallResult(GKC::SystemCallResults::Invalid));  //throw
	}
	static void ThrowMemory()
	{
		throw GKC::OutOfMemoryException();  //throw
	}
	static void ThrowOverflow()
	{
		throw GKC::OverflowException();  //throw
	}
	static void ThrowUnexpected()
	{
		throw GKC::Exception(GKC::CallResult(GKC::SystemCallResults::Unexpected));  //throw
	}
};

// Containers

template <class TIterator>
class IteratorTraits
{
public:
	typedef typename TIterator::EType  ValueType;
	typedef TIterator  IteratorType;

	static intptr_t CalcDistance(const IteratorType& begin, const IteratorType& end) noexcept
	{
		return end.CalcDelta(begin);
	}
	static const ValueType& Get(const IteratorType& it) noexcept
	{
		return it.get_Value();
	}
	static ValueType& Get(IteratorType& it) noexcept
	{
		return it.get_Value();
	}
	static IteratorType Move(const IteratorType& it, intptr_t delta) noexcept
	{
		IteratorType ret(it);
		ret.MoveDelta(delta);
		return ret;
	}
	static void Move(intptr_t delta, IteratorType& it) noexcept
	{
		it.MoveDelta(delta);
	}
	static void ToNext(IteratorType& it) noexcept
	{
		it.MoveNext();
	}
	static void ToPrev(IteratorType& it) noexcept
	{
		it.MovePrev();
	}
	template <class TFunctor>
	static void ForEach(const IteratorType& itb, const IteratorType& ite, const TFunctor& func)
	{
		GKC::ForEach(itb, ite, func);
	}
};

template <typename T>
class ArrayTraits
{
public:
	typedef T  ValueType;
	typedef GKC::UniqueArray<T>  ArrayType;

	static uintptr_t GetSize(const ArrayType& arr) noexcept
	{
		return arr.GetCount();
	}
	static const ValueType* GetAddress(const ArrayType& arr) noexcept
	{
		return &arr[0];
	}
	static ValueType* GetAddress(ArrayType& arr) noexcept
	{
		return &arr[0];
	}
	static const ValueType& GetAt(const ArrayType& arr, uintptr_t index) noexcept
	{
		return arr[index];
	}
	static ValueType& GetAt(ArrayType& arr, uintptr_t index) noexcept
	{
		return arr[index];
	}
	static void Clear(ArrayType& arr) noexcept
	{
		arr.RemoveAll();
	}
	static void SetSize(ArrayType& arr, uintptr_t size)
	{
		arr.SetCount(size);  //may throw
	}
	static void Append(const ValueType& src, ArrayType& arr)
	{
		arr.Add(src);  //may throw
	}
	static void RemoveAt(ArrayType& arr, uintptr_t index) noexcept
	{
		arr.RemoveAt(index);
	}
	template <typename... Args>
	static void InsertAt(ArrayType& arr, uintptr_t index, Args&&... args)
	{
		arr.InsertAt(index, 1, rv_forward<Args>(args)...);
	}
};

template <typename Tchar>
class CharTraits
{
public:
	typedef Tchar  CharType;

	static CharType ToLower(CharType ch) noexcept
	{
		return char_lower(ch);
	}
	static CharType ToUpper(CharType ch) noexcept
	{
		return char_upper(ch);
	}
	static bool IsAlnum(CharType ch) noexcept
	{
		return char_is_alnum(ch);
	}
	static bool IsAlpha(CharType ch) noexcept
	{
		return char_is_alpha(ch);
	}
	static bool IsCntrl(CharType ch) noexcept
	{
		return char_is_cntrl(ch);
	}
	static bool IsGraph(CharType ch) noexcept
	{
		return char_is_graph(ch);
	}
	static bool IsLower(CharType ch) noexcept
	{
		return char_is_lower(ch);
	}
	static bool IsUpper(CharType ch) noexcept
	{
		return char_is_upper(ch);
	}
	static bool IsDigit(CharType ch) noexcept
	{
		return char_is_digit(ch);
	}
	static bool IsXdigit(CharType ch) noexcept
	{
		return char_is_xdigit(ch);
	}
	static bool IsBlank(CharType ch) noexcept
	{
		return char_is_blank(ch);
	}
	static bool IsSpace(CharType ch) noexcept
	{
		return char_is_space(ch);
	}
	static bool IsPrint(CharType ch) noexcept
	{
		return char_is_print(ch);
	}
	static bool IsPunct(CharType ch) noexcept
	{
		return char_is_punct(ch);
	}
	static uintptr_t GetLength(const CharType* sz) noexcept
	{
		return calc_string_length(sz);
	}
};

template <class TString>
class StringTraits
{
public:
	typedef typename TString::EType  CharType;
	typedef TString  StringType;

	static uintptr_t GetLength(const StringType& str) noexcept
	{
		return str.GetLength();
	}
	static const CharType* GetAddress(const StringType& str) noexcept
	{
		return &str[0];
	}
	static CharType* GetAddress(StringType& str) noexcept
	{
		return &str[0];
	}
	static void Clear(StringType& str) noexcept
	{
		str.Clear();
	}
	static void Append(CharType ch, StringType& str)
	{
		GKC::StringOpHelper::Append(ch, str);  //may throw
	}
	static void Append(const CharType* sz, StringType& str)
	{
		GKC::StringUtilHelper::Append(GKC::ConstStringT<CharType>(sz, calc_string_length(sz)), str);  //may throw
	}
	static void Append(const StringType& src, StringType& str)
	{
		GKC::StringUtilHelper::Append(src, str);  //may throw
	}
};

////////////////////////////////////////////////////////////////////////////////
}
////////////////////////////////////////////////////////////////////////////////
#endif
////////////////////////////////////////////////////////////////////////////////
